package com.xzj.getway.service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.xzj.admin.base.constants.BaseConstants;
import com.xzj.admin.base.domain.gateway.XzjRouteDefinition;
import com.xzj.getway.cache.GatewayCache;
import com.xzj.getway.util.GateWayUtil;
import com.xzj.getway.util.Md5Util;
import jakarta.annotation.Resource;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @program: xzj-admin
 * @ClassName: DynamicRouteServiceImpl
 * @description: 动态路由实现类
 * @author: XiaZunJun
 * @create: 2024-10-11 15:02
 */
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {
    @Resource
    private RouteDefinitionWriter routeDefinitionWriter;


    @Resource
    private ApplicationEventPublisher publisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
        this.publisher = eventPublisher;
    }

    //新增路由
    private void add(RouteDefinition routeDefinition){
        /**
         * 新增的Actuator Endpoint，刷新路由的时候，先加载路由配置到内存中，
         */
        routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
    }

    // 使用RefreshRoutesEvent事件刷新内存中路由配置。
    public void publish(){
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }

    public void refresh(List<XzjRouteDefinition> myRouteDefinitions){
        boolean isRefresh = false;
        for(XzjRouteDefinition myRouteDefinition : myRouteDefinitions){
            RouteDefinition routeDefinition = GateWayUtil.buildRouteDefinition(myRouteDefinition);
            String jsonMd5 = Md5Util.objectToMd5(JSON.toJSONString(routeDefinition));
            if(!GatewayCache.containsKey(routeDefinition.getId(), jsonMd5)){
                isRefresh = true;
                GatewayCache.put(routeDefinition.getId(), routeDefinition, jsonMd5);
                add(routeDefinition);
            }
        }
        if(isRefresh){
            publish();
        }
    }

    // 删除路由
    public void delete(String id){
        routeDefinitionWriter.delete(Mono.just(id)).subscribe();
        GatewayCache.remove(id);
    }

    @Resource
    private RedisTemplate<String,String> redisTemplate;

    public void refreshAll(){
        HashOperations<String,String,String> hashOperations = redisTemplate.opsForHash();
        List<XzjRouteDefinition> myRouteDefinitions = new ArrayList<>();
        Map<String,String> keyValues = hashOperations.entries(BaseConstants.REDIS_GATEWAY_ROUTER_KEY);
        for(String key : keyValues.keySet()){
            XzjRouteDefinition myRouteDefinition = JSONObject.parseObject(keyValues.get(key), XzjRouteDefinition.class);
            myRouteDefinitions.add(myRouteDefinition);
        }
        refresh(myRouteDefinitions);
    }
}
